<!--
  @Descripttion：带参照的输入框组件
  @Author：zqy
  @Date：2020-10-17 14:27:39
  @Last Modified by：zqy
  @Last Modified time：2020-10-17 14:27:39
-->
<template>
  <div>
    <div class="input-with-search">
      <el-autocomplete
        ref="myAutocomplete"
        v-model="selLable" 
        :placeholder="placeholder"
        :fetch-suggestions="remoteSelections"
        :trigger-on-focus="focusQuery"
        value-key="label"
        size="mini"
        @select="handleSelectChange"
        @blur="handleBlur"
        :disabled="disabled"
        :clearable="clearable"
        @clear="clearSearch"
      >
        <i slot="suffix" class="el-input__icon el-icon-search" :class='{"btn-disabled":disabled}'  @click.self="openDialog" />
        <template slot-scope="props">
          <div class="space_nomorl" :class="{'selected':checkSelected(props.item.value)}">{{ props.item.label }}</div>
        </template>
      </el-autocomplete>
    </div>
    <el-dialog
      ref="refDlg"
      v-el-drag-dialog 
      :title="config.title"
      :visible.sync="dialogShow"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      :width="dlgWidth"
      :append-to-body="dlgToBody!==false"
      custom-class="qup-search-dlg"
      :show-close="false"
      @close="closeDialog"              
      @click.native.stop=""
    >
      <div slot="title" class="search-dlg-head">
        <div class="title">{{config.title}}</div>
        <div v-if="!hideSearchBar"  class="search-form-bar" @keydown.enter="handleSearch" @mousemove.stop=''>
          <el-input size="mini" placeholder="请输入关键字" v-model="queryKeyWord" class="input-with-search">
            <el-button slot="append" size="mini" type="primary" @click="handleSearch">搜索</el-button>
          </el-input>
        </div>
      </div>
      <div class="qup-search-dlg">
        <el-tabs v-model="activeTab" @tab-click="handleTabClick">
          <el-tab-pane label="全部" name="all">
            <div class="table-list-box">
              <el-table
                v-loading="tableLoading"
                ref="refTable"
                style="width: 100%"
                :data="tableData"
                :height="300"
                :row-key="primaryKey"
                :row-class-name="tableRowClassName"
                header-row-class-name="table-list-header"
                highlight-current-row
                border
                @selection-change="handleSelectionChange"
                @row-click="tableRowHandle"
                @row-dblclick="tableRowDblclick"
              >
                <el-table-column v-if="multiple" type="selection" reserve-selection  width="50" fixed="left" align="center"/>
                <el-table-column 
                  v-for="(item,index) in cloumnData" 
                  :key="index" 
                  :prop="item.prop" 
                  :label="item.title" 
                  :min-width="item.width || 150" 
                  :show-overflow-tooltip="item.showOverflow===true?true:false"
                  sortable
                />
              </el-table>
            </div>
            <template v-if="!this.config.hidePage">
              <el-button v-if="loadMore && tableData.length" class="btn-load-more" type="text" size="mini" @click="handlerLoadMore">
                加载更多数据 <i class="el-icon-arrow-down" />
              </el-button>
              <div v-if="!loadMore && tableData.length" class="no-more">没有更多数据了</div>
            </template>
          </el-tab-pane>
          <el-tab-pane v-if="multiple" :label="`已选择(${tableSelectedData.length})`" name="selected">
            <div class="table-list-box">
              <el-table
                ref="refSelTable"
                style="width: 100%"
                :data="tableSelectedData"
                :height="340"
                header-row-class-name="table-list-header"
                highlight-current-row
                border
              >
                <el-table-column width="50" fixed="left" align="center">
                  <template slot="header" slot-scope="scope">
                      <span class="btn-clear" @click="handleClearAll">清空</span>
                  </template>
                  <template v-slot="{row}">
                    <i class="el-icon-error btn-remove" @click="handleRemoveSelecte(row)"></i>
                  </template>
                </el-table-column>
                <el-table-column 
                  v-for="(item,index) in cloumnData" 
                  :key="index" 
                  :prop="item.prop" 
                  :label="item.title" 
                  :min-width="item.width || 150" 
                />
              </el-table>
            </div>
            <!-- <div class="no-more"></div> -->
          </el-tab-pane>
        </el-tabs>
      </div>
      <div slot="footer">
        <el-button size="mini" @click="closeDialog">取消</el-button>
        <el-button size="mini" type="primary" class="btn-submit" @click="handleSubmit">确定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import {getRemoteData,getTableData} from "./apis";
import drag from '../../directives/el-drag-dialog/drag'
export default {
  name: 'InputWithDialog',
  components: {},
  directives:{
    'el-drag-dialog':drag
  },
  props: {
    value:{
      type:[String,Array],
      default:'',
    }, // 默认值 [{label,value}]
    remoteUrl:{
      type:String,
      default:''
    }, // apiUrl地址
    props:{
      type:Object,
      default:()=>{
        return {label: 'label', value: 'value'}
      }
    }, // 下拉选项的配置选项(lable:显示名称，value：值)
    showField:{
      type:String,
      default:''
    }, // 输入框显示值对应字段
    requestMethod:{
      type:String,
      default:'get'
    },// 下拉搜索请求方式
    paramField:{
      type:String,
      default:'paramKeyword'
    }, // 输入框关键字查询时的入参字段名称
    placeholder:{
      type:String,
      default:'请输入搜索'
    },
    multiple:{
      type:Boolean,
      default:false
    },//是否允许多选
    focusQuery:{
      type:Boolean,
      default:true
    },// 是否获取焦点时立即筛选
    optionData:{
      type:Array,
      default:()=>[]
    },// 默认下拉框数据集合
    config:{
      type:Object,
      required: true,
      default:()=>{
        return {
          title:'',//弹窗标题
          width:'600px',//弹窗宽度
          interfacePath:'',//数据查询接口地址
          method:'post',// 请求方式
          order:'desc',// 排序方式（desc/asc，降序/升序）
          sort:'',//排序字段名称
          paramField:'paramKeyword', // 弹窗关键字的字段名
          pageSize:15,// 分页数量
          filtersRaw:[],// 查询参数
          paramsRaw:{},// 查询参数
          rowKey:'', // 表格行唯一标识key
          hidePage:true,// 是否隐藏分页
          setting:[
            {prop:'name',title:'名称',width:'150'},
            {prop:'code',title:'编码',width:'150'},
          ],
          apiHeader:null, // 数据请求的header
        }
      }, // 弹窗接口操作相关配置
    },
    disabled:{
      type:Boolean,
      default:false
    }, // 是否禁用
    hideSearchBar:{
      type:Boolean,
      default:false
    }, // 是否隐藏条件搜索框，当条件搜索框被隐藏时，关键字搜索失效
    dlgToBody:{
      type:Boolean,
      default:true
    },
    clearable:{
      type:Boolean,
      default:false
    },
    beforeConfirm: {
      type: Function,
      default: function() {
        return true
      }
    },
  },
  data() {
    return {
      remoteLoading: false, // 远程搜索加载
      selectedData:[], // 当前所选中的数据对象集合，对应props中{label,value}，如：[{label,value}]
      selLable:'', // 当前选中显示值，对应props的label
      dialogShow:false,
      activeTab:'all',
      tableData:[],//表格全部数据
      selectedRows:[],//表格已选择数据行
      singleRows:[],//单选数据行
      tableSelectedData:[],//已选表格数据
      loadMore:false,//是否加载更多
      queryKeyWord:'',//查询关键字
      page:1, 
      pageSize:15,
      tableLoading:false
    }
  },

  computed: {
    // 输入框显示值对应字段
    showValueField(){
      const propLable=(this.props && this.props.label) || 'lable'
      return this.showField ||  propLable
    },
    // 表格主键
    primaryKey(){
      if(this.config && this.config.rowKey){
        return this.config.rowKey
      }
      return this.props.value || 'id'
    },
    // 表格列
    cloumnData(){
      return this.config.setting || []
    },
    // 表格查询
    tableQueryMethod(){
      return this.config.method && this.config.method==='get'?'get':'post'
    },
    // 弹窗宽度
    dlgWidth(){
      let width='600px'
      if(this.config && this.config.width){
        let str=`${this.config.width}`
        if(str.indexOf('%')>0 || str.indexOf('px')>0){
          width=this.config.width
        }else{
          width=`${str}px`
        }
      }
      return width
    },
    // 输入框关键字搜索接口
    inputQueryApi(){
      let apiUrl = this.remoteUrl || ''
      if(!this.remoteUrl && (!this.optionData || this.optionData.length===0)){
        apiUrl = this.config.interfacePath
      }
      return apiUrl
    },
    selectValue(){
      const values= this.selectedData.map(v=>{
        return v.value || v[this.props.value]
      })
      return values.join(',')
    }
  },
  watch:{
    value:{
      handler(val,oldVal){
        let labels=[]
        let resData=[]
        if(val && Array.isArray(val) && val.length){
          resData=val.map(v=>{
            const label=v.label || v[this.props.label]
            const res={
              label,
              value:v.value || v[this.props.value]
            }
            if(this.showField){
              const showLable=v[this.showValueField] || label
              res[this.showValueField]=showLable
              labels.push(showLable)
            }else{
              labels.push(label)
            }
            return {...v,...res}
          })
        }
        this.selLable=labels.join(',')
        this.selectedData=resData
      },
      deep:true,
      immediate:true
    },
    selectValue(val,oldVal){
      // this.$emit('change', this.selectedData)
    }
  },
  created(){
    if(this.config.pageSize){
      this.pageSize=this.config.pageSize
    }
  },
  methods: {
    changeData(data){
      const resLabel=[]
      const newValue=[]
      const values=data.map(v=>{
        const tmp={
          label: v.label || v[this.props.label],
          value:v.value || v[this.props.value]
        }
        
        if(this.showField){
          const showLable=v[this.showValueField] || ''
          tmp[this.showValueField]=showLable
          resLabel.push(showLable)
        }else{
          resLabel.push(tmp.label)
        }

        newValue.push(tmp.value)
        return {...v,...tmp}
      })
      this.selLable = resLabel.join(',')
      if(this.selectValue!==newValue.join(',')){
        this.selectedData = values
        this.$emit('input', values)
        this.$emit('change', values)
      }
    },
    checkSelected(val){
      const result=this.selectedData.filter(v=>{
        const value=v.value || v[this.props.value]
        return value===val
      })
      return result.length
    },
    // 输入框选值改变
    handleSelectChange(item) {
      if(this.disabled) return
      const resData=item && item instanceof Object ? [item] : []
      const arrTmp=resData.filter(v=>{
        return v.label !=='无匹配结果'
      })
      // console.log('handleSelectChange',arrTmp)
      
      const before = this.beforeConfirm(resData)
      if(before && before.then){
        before.then(()=>{
          this.changeData(resData)
          this.$emit('blur')
        }).catch(()=>{
          this.selectedData = []
          this.selLable = ''
        })
      }else if(before!==false){
        this.changeData(resData)
        this.$emit('blur')
      }else{
          this.selectedData = []
          this.selLable = ''
      }
      
      // this.changeData(arrTmp)
      // this.$emit('blur')
    },
    // 根据输入关键字搜索
    remoteSelections(queryString,cb) {
      if(!this.inputQueryApi){
        // 若不存在远程连接地址，则搜索默认选项内容
        let results=[]
        if(this.optionData && this.optionData.length){
          const restaurants = this.optionData;
          if(!this.hideSearchBar){
            results = queryString ? restaurants.filter(v=>{
              return (v.label.toLowerCase().indexOf(`${queryString.toLowerCase()}`) >=0);
            }) : restaurants;
          }
        }    
        cb(results)
        return
      }

      // 远程搜索
      const defaultProps = this.props || { label: 'label', value: 'value' }
      const rqUrl = this.inputQueryApi
      let rqMethod = this.requestMethod || 'get'
      const emptyData=[{value:'',label:'无匹配结果'}]
      /* if(queryString && queryString.length){
        params = {[this.paramField || 'paramKeyword']:queryString}
      } */
      let paramKey=this.paramField
      if(this.inputQueryApi === this.config.interfacePath){
        if(rqMethod!==this.tableQueryMethod){
          rqMethod = this.tableQueryMethod
        }
        if(this.paramField!==this.config.paramField){
          paramKey=this.config.paramField
        }
      }

      let params=null

      let paramsRaw={
        [paramKey || 'paramKeyword'] : queryString
      }
      if(rqMethod==='post'){
        params = new FormData()
        params.append('page', 1)
        params.append('rows',10)
        if(rqUrl===this.config.interfacePath){
          params.append('sort', this.config.sort || '')
          params.append('order', this.config.order || 'desc')
          if(this.config.filtersRaw && this.config.filtersRaw.length){
            params.append('filtersRaw', JSON.stringify(this.config.filtersRaw))
          }
          if(this.hideSearchBar){
            // 隐藏搜索框则关键字搜索失效
            paramsRaw={}
          }
          if(this.config.paramsRaw){
            paramsRaw={...paramsRaw,...this.config.paramsRaw}
          }
        }
        params.append('paramsRaw',JSON.stringify(paramsRaw))
      }else{
        if(!this.hideSearchBar){
          // 隐藏搜索框则关键字搜索失效
          params = paramsRaw
          if(this.inputQueryApi === this.config.interfacePath && this.config.paramsRaw){
            params={...params,...this.config.paramsRaw}
          }
        }
      }
      const apiHeader = this.config.apiHeader || null
      getRemoteData(rqMethod,rqUrl,params,apiHeader).then(res => {
        let records=[]
        if(res.data){
          records= res.data.records || res.data
        }
        const dataList = records.map(item => {
          const res= { value: item[defaultProps.value], label: item[defaultProps.label] }
          return {...item,...res}
        })
        cb( dataList.length ? dataList : emptyData )
      }).catch(()=>{
        cb(emptyData)
      })
    },
    clearSearch() {
      // this.$refs.myAutocomplete.handleFocus()
      this.selectedData = []
      this.selLable = ''
      this.$emit('input', [])
      this.$emit('change', [])
    },
    // 输入框失去焦点时验证输入值是否有效
    handleBlur(){
      let resData=[]
      if(this.selLable){
        const labels=this.selLable.split(',')
        // console.log(JSON.stringify(this.selectedData))
        resData=this.selectedData.filter(v=>{
          let index=labels.indexOf(v.label || v[this.props.label])
          if(this.showField){
            index=labels.indexOf(v[this.showValueField])
          }
          return index>-1
        })
      }
      // console.log('blur',resData)
      
      this.changeData(resData)

      // 处理失去焦点
      setTimeout(() => {
        if(!this.dialogShow){
          this.$emit('blur')
        }
      }, 200);
    },
    /***
     * 搜索数据
     * @params {String} keyword  关键字
     * @params {function} cb  回调
     */
    searchData(keyword,cb){
      this.remoteSelections(keyword,cb)
    },
    // 打开弹窗
    openDialog(){
      if(this.disabled) return
      // 关闭下拉框
      if (this.$refs.myAutocomplete && this.$refs.myAutocomplete.$children && this.$refs.myAutocomplete.$children[1]) {
        this.$refs.myAutocomplete.$children[1].showPopper = false
      }
      this.dialogShow=true
      
      /* if(this.tableData.length===0){
        this.loadTableData()
      } */
      this.loadTableData()
      this.resetTableSelect()
    },
    // 关闭弹窗
    closeDialog(){
      this.queryKeyWord=''
      this.dialogShow=false
      this.page=1
      this.$emit('blur')
    },
    // 弹窗确定选择
    handleSubmit(){
      let  resData =[]
      const rows = this.multiple ? this.tableSelectedData : this.singleRows
      if(rows && rows.length){
        resData=rows ? rows.map(v=>{
          const res={
            label:v[this.props.label],
            value:v[this.props.value]
          }
          return {...v,...res}
        }) : []
      }
      const before = this.beforeConfirm(resData)
      if(before && before.then){
        before.then(()=>{
          this.changeData(resData)
          this.closeDialog()
        })
      }else if(before!==false){
        this.changeData(resData)
        this.closeDialog()
      }
    },
    handleTabClick(){

    },
    // 查询表格数据
    loadTableData(){
      let params=null
      let paramsRaw={
        [this.config.paramField || 'paramKeyword'] : this.queryKeyWord.trim()
      }
      /* if(this.queryKeyWord && this.queryKeyWord.length){
        paramsRaw={
          [this.config.paramField || 'paramKeyword'] : this.queryKeyWord
        }
      } */
      if(this.tableQueryMethod==='post'){        
        params = new FormData()
        if(!this.config.hidePage){
          params.append('page', this.page)
          params.append('rows', this.pageSize)
        }
        params.append('sort', this.config.sort || '')
        params.append('order', this.config.order || 'desc')
        if(this.config.filtersRaw && this.config.filtersRaw.length){
          params.append('filtersRaw', JSON.stringify(this.config.filtersRaw))
        }
        if(this.hideSearchBar){
          // 隐藏搜索框则关键字搜索失效
          paramsRaw={}
        }
        if(this.config.paramsRaw){
          paramsRaw={...paramsRaw,...this.config.paramsRaw}
        }
        params.append('paramsRaw',JSON.stringify(paramsRaw))
      }else{
        // 隐藏搜索框则关键字搜索失效
        params = this.hideSearchBar?{}:paramsRaw
        if(this.config.paramsRaw){
          params={...params,...this.config.paramsRaw}
        }
      }
      this.tableLoading=true
      const apiHeader = this.config.apiHeader || null
      getTableData(this.tableQueryMethod,this.config.interfacePath,params,apiHeader).then(res=>{
        this.tableLoading=false
        if(this.tableQueryMethod==='get'){
          if (Object.keys(res.data).indexOf('records') === -1) {
            this.tableData=res.data || []
          } else {
            this.tableData=res.data.records || []
          }
          this.loadMore=false
          return
        }
        const records = (res.data && res.data.records) || []
        this.loadMore = records.length === this.pageSize
        this.tableData = this.page===1 ? records : this.tableData.concat(records)
      }).catch(() => {
        this.tableLoading=false
      });
    },
    // 加载更多
    handlerLoadMore(){
      this.page += 1
      this.loadTableData()
    },
    // 搜索
    handleSearch(){
      this.page=1
      this.loadTableData()
    },
    // 点击表格行选中
    tableRowHandle(row, column, event) {
      if(this.multiple){
        let index=-1
        if(this.tableSelectedData && this.tableSelectedData.length>0){
          index=this.tableSelectedData.findIndex(v=>v[this.primaryKey] === row[this.primaryKey])
        }
        this.$refs.refTable.toggleRowSelection(row, index===-1)
      }else{
        this.singleRows=[row]
      }
    },
    // 双击表格行
    tableRowDblclick(row, event) {
      if(this.multiple) return
      this.singleRows=[row]
      this.handleSubmit()
    },
    // 设置表格多选行高亮
    tableRowClassName({ row, rowIndex }) {
      const filterArr = this.selectedRows.filter(v => v[this.primaryKey] === row[this.primaryKey])
      return filterArr.length > 0 ? 'selected-highlight' : ''
    },
    // 处理选项更新
    handleSelectionChange(rows){
      const cancelArr = this.tableSelectedData.map(data => {
        const index = rows.findIndex(row => row[this.primaryKey]  === data[this.primaryKey] )
        return index === -1 ? data : false
      })

      if (cancelArr && cancelArr.length > 0) {
        cancelArr.forEach(row => {
          const rowIndex = this.tableSelectedData.findIndex(v => v[this.primaryKey]  === row[this.primaryKey] )
          if (rowIndex > -1) {
            this.tableSelectedData.splice(rowIndex, 1)
          }
        })
      }

      this.selectedRows = rows
      rows.forEach(row => {
        const rowIndex = this.tableSelectedData.findIndex(v => v[this.primaryKey] === row[this.primaryKey])
        if (rowIndex === -1) {
          this.tableSelectedData.push(row)
        }
      }) 
    },
    // 移除已选择数据
    handleRemoveSelecte(row){
      const rowIndex = this.tableSelectedData.findIndex(v => v[this.primaryKey] === row[this.primaryKey])
      if (rowIndex > -1) {
        this.tableSelectedData.splice(rowIndex, 1)
      }

      const tmp=this.tableData.filter(v=>v[this.primaryKey]===row[this.primaryKey])
       if (tmp.length > 0) { // 在当前页表格数据中则取消选中
        this.$refs.refTable.toggleRowSelection(tmp[0], false)
      } else { // 未在当前表格数据中，则加入到取消选中的数据集中，并从已选数据表中删除
        const index = this.selectedRows.indexOf(row)
        this.selectedRows.splice(index, 1)
      }
    },
    //清空所有已选择数据
    handleClearAll(){
      this.tableSelectedData = []
      this.selectedRows.map(row=>{
        this.$refs.refTable.toggleRowSelection(row, false)
      })
      this.$refs.refTable.clearSelection()
    },
    // 根据输入框选中值重置表格选中项
    resetTableSelect(){
      if(this.tableSelectedData && this.tableSelectedData.length){
        // 表格选中项存在，则移除表格选中项中不属于输入框选中值的表格行
        if(this.selectedData && this.selectedData.length){
          const removeRow=this.tableSelectedData.filter(row=>{
            const index = this.selectedData.findIndex(d=>d.value===row[this.primaryKey])
            return index===-1
          })
          removeRow.forEach(row=>{
            this.handleRemoveSelecte(row)
          })
        }else{
          this.handleClearAll()
        }
      }
    }
  }
}
</script>
<style lang='scss' scoped>
@import "../../../theme/qup-theme";
.input-with-search{
  width:100%; 
  position: relative;
  .el-autocomplete{
    width: 100%;
  }

  // .input-box{
  //   position: absolute;
  //   left:0;
  //   right: 0;
  //   top: 0;
  //   bottom: 0;
  //   z-index:9
  // }
  /deep/ .el-input__suffix{
    width:22px;
    height: 22px;
    line-height: 22px;
    top: 50%;
    background: #fff;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    .el-input__icon{
      line-height: 22px;
    }
    .btn-disabled{
      background:#f5f7fa
    }
    .el-input__clear{
      position: absolute;
      right:22px;
      top: 0;
      z-index: 1;
      background-color: #fff;
    }
  }
  /deep/ .el-select{
    width: 100%;
    height: 29px;
    .el-input__suffix{
      right: 30px;
    }
  }
  /deep/ .el-input__inner{
    height: 28px;
    line-height: 28px;
  }
  
  /deep/ .el-input.is-focus .el-input__inner{
    border-color: $qup-color-primary !important;
  }

  /deep/ .el-input__inner:focus{
    border-color: $qup-color-primary !important;
  }
  /deep/ .el-select__tags{
    max-height: 26px !important;
    height: 26px !important;
    overflow: hidden;
    white-space:nowrap;
  }
  .qup-select-input-search{
    position: absolute;
    right: 0;
    top: 0;
    z-index: 9;
    width: 35px;
    height: 28px;
    line-height: 30px;
    color: #c0c4cc;
    text-align: center;
    cursor: default;
  }
}


.search-dlg-head{
  display: flex;
  align-items: center;
  justify-content: space-between;
  .title{
    font-size: 14px;
    font-weight: bold;
  }
  /deep/ .el-input.is-active .el-input__inner, 
  /deep/ .el-input__inner:focus{
    border-color:$qup-color-primary !important;
  }
}
.qup-search-dlg{
  /deep/ .el-tabs__active-bar{
    background-color:$qup-color-primary;
  }
  /deep/ .el-tabs__item{
    line-height: 18px;
    height: 24px;
  }
  
  /deep/ .el-tabs__item:hover{
    color:$qup-color-primary;
  } 
  /deep/ .el-tabs__item.is-active{
    color:$qup-color-primary;
    font-weight: bold;
  }
  .btn-load-more{
    margin-top: 10px;
    padding: 0 !important;
    color:$qup-color-primary;
  }
  .btn-submit{
    background-color:$qup-color-primary;
    border-color:$qup-color-primary;
  }
  .btn-clear{
    cursor: pointer;
    color:$qup-color-primary;
  }
  .no-more{
    margin-top: 10px;
    height: 28px;
    line-height: 28px;
    color: #bebebe;
  }
  .btn-remove{
    cursor: pointer;
    font-size: 18px;
    color: #bebebe;
    &:hover{
      color:$qup-color-primary;
    }
  }
}
</style>
